package server

import (
	"fmt"
	"math"
	"math/rand"
	"server5/Interface"
	"server5/protobuf"
	"server5/utils"
	"sync/atomic"
	"time"
)

type Unit struct {
	id               int32
	unitType         int32 //兵种类型
	level            int32 //兵种等级
	player           Interface.IPlayer
	status           int32 //状态
	allHp            int32
	nowHp            int32     //加锁
	attackPowerUpper int32     //攻击力上限
	attackPowerLower int32     //攻击力下限
	attackRange      float64   //攻击范围
	detectRange      float64   //感知范围
	attackSpeed      float64   //攻击速度
	moveSpeed        float64   //移动速度
	posX             int32     //加锁
	posZ             int32     //加锁
	path             [][]int32 //加锁
	newPath          [][]int32
	attackTarget     Interface.IUnit //加锁
	attackedTarget   Interface.IUnit //加锁

	node 			int		//记录当前走到路径的第几个点
	lastAttackTime	time.Time
	lastMoveTime	time.Time
}

func (u *Unit) UnitType() int32 {
	return u.unitType
}

func (u *Unit) DetectRange() float64 {
	return u.detectRange
}

func (u *Unit) SetDetectRange(detectRange float64) {
	u.detectRange = detectRange
}

func (u *Unit) AttackRange() float64 {
	return u.attackRange
}

func (u *Unit) SetAttackRange(attackRange float64) {
	u.attackRange = attackRange
}

func NewInfantry(id int32,level int32,player Interface.IPlayer) Interface.IUnit{
	u := &Unit{
		id:          id,
		unitType:    utils.Infantry,
		level:       level,
		player:      player,
		status:      utils.Static,
		attackRange: utils.InfantryAttackRange,
		detectRange: utils.InfantryDetectRange,
		attackSpeed: utils.InfantryAttackSpeed,
		moveSpeed:   utils.InfantryMoveSpeed,
	}
	switch u.level {
	case 1:
		u.allHp = utils.InfantryAllHp1
		u.nowHp = utils.InfantryAllHp1
		u.attackPowerLower = utils.InfantryAttackPowerLower1
		u.attackPowerUpper = utils.InfantryAttackPowerUpper1
	case 2:
		u.allHp = utils.InfantryAllHp2
		u.nowHp = utils.InfantryAllHp2
		u.attackPowerLower = utils.InfantryAttackPowerLower2
		u.attackPowerUpper = utils.InfantryAttackPowerUpper2
	case 3:
		u.allHp = utils.InfantryAllHp3
		u.nowHp = utils.InfantryAllHp3
		u.attackPowerLower = utils.InfantryAttackPowerLower3
		u.attackPowerUpper = utils.InfantryAttackPowerUpper3
	}
	return u
}


func NewArcher(id int32,level int32,player Interface.IPlayer) Interface.IUnit{
	u := &Unit{
		id:          id,
		unitType:    utils.Archer,
		level:       level,
		player:      player,
		status:      utils.Static,
		attackRange: utils.ArcherAttackRange,
		detectRange: utils.ArcherDetectRange,
		attackSpeed: utils.ArcherAttackSpeed,
		moveSpeed:   utils.ArcherMoveSpeed,
	}
	switch u.level {
	case 1:
		u.allHp = utils.ArcherAllHp1
		u.nowHp = utils.ArcherAllHp1
		u.attackPowerLower = utils.ArcherAttackPowerLower1
		u.attackPowerUpper = utils.ArcherAttackPowerUpper1
	case 2:
		u.allHp = utils.ArcherAllHp2
		u.nowHp = utils.ArcherAllHp2
		u.attackPowerLower = utils.ArcherAttackPowerLower2
		u.attackPowerUpper = utils.ArcherAttackPowerUpper2
	case 3:
		u.allHp = utils.ArcherAllHp3
		u.nowHp = utils.ArcherAllHp3
		u.attackPowerLower = utils.ArcherAttackPowerLower3
		u.attackPowerUpper = utils.ArcherAttackPowerUpper3
	}
	return u
}

func NewMage(id int32,level int32,player Interface.IPlayer) Interface.IUnit{
	u := &Unit{
		id:          id,
		unitType:    utils.Mage,
		level:       level,
		player:      player,
		status:      utils.Static,
		attackRange: utils.MageAttackRange,
		detectRange: utils.MageDetectRange,
		attackSpeed: utils.MageAttackSpeed,
		moveSpeed:   utils.MageMoveSpeed,
	}
	switch u.level {
	case 1:
		u.allHp = utils.MageAllHp1
		u.nowHp = utils.MageAllHp1
		u.attackPowerLower = utils.MageAttackPowerLower1
		u.attackPowerUpper = utils.MageAttackPowerUpper1
	case 2:
		u.allHp = utils.MageAllHp2
		u.nowHp = utils.MageAllHp2
		u.attackPowerLower = utils.MageAttackPowerLower2
		u.attackPowerUpper = utils.MageAttackPowerUpper2
	case 3:
		u.allHp = utils.MageAllHp3
		u.nowHp = utils.MageAllHp3
		u.attackPowerLower = utils.MageAttackPowerLower3
		u.attackPowerUpper = utils.MageAttackPowerUpper3
	}
	return u
}


func NewBoss(id int32,level int32,player Interface.IPlayer) Interface.IUnit{
	u := &Unit{
		id:          id,
		unitType:    utils.Boss,
		level:       level,
		player:      player,
		status:      utils.Static,
		attackRange: utils.BossAttackRange,
		detectRange: utils.BossDetectRange,
		attackSpeed: utils.BossAttackSpeed,
		moveSpeed:   utils.BossMoveSpeed,
	}
	switch u.level {
	case 1:
		u.allHp = utils.BossAllHp1
		u.nowHp = utils.BossAllHp1
		u.attackPowerLower = utils.BossAttackPowerLower1
		u.attackPowerUpper = utils.BossAttackPowerUpper1
	case 2:
		u.allHp = utils.BossAllHp2
		u.nowHp = utils.BossAllHp2
		u.attackPowerLower = utils.BossAttackPowerLower2
		u.attackPowerUpper = utils.BossAttackPowerUpper2
	case 3:
		u.allHp = utils.BossAllHp3
		u.nowHp = utils.BossAllHp3
		u.attackPowerLower = utils.BossAttackPowerLower3
		u.attackPowerUpper = utils.BossAttackPowerUpper3
	}
	return u
}

func (u *Unit) NewPath() [][]int32 {
	return u.newPath
}

func (u *Unit) SetNewPath(newPath [][]int32) {
	u.newPath = newPath
}

//OK
func (u *Unit) AttackedTarget() Interface.IUnit {
	return u.attackedTarget
}

//OK
func (u *Unit) SetAttackedTarget(attackedTarget Interface.IUnit) {
	u.attackedTarget = attackedTarget
}

func (u *Unit) Dead() {
	if u.status == utils.Death {
		return
	}
	if u.nowHp <= 0 {
		//Debug

		var attackUnitInfoMsg protobuf.AttackUnitInfoMsg
		attackUnitInfoMsg.Id = u.Id()
		attackUnitInfoMsg.NowHp = u.NowHp()
		attackUnitInfoMsg.Status = u.Status()
		u.player.GameRoom().Broadcast(protobuf.MsgType_AttackUnitInfo,&attackUnitInfoMsg)

		fmt.Println(u.Id(),"号士兵死亡")
		u.player.RemoveUnit(u.id)
		u.player.GameRoom().RemoveUnit(u.id)
		u.player.ReCalculate()
		u.player = nil
		u.attackTarget = nil
		u.attackedTarget = nil
		u.path = nil
		u.status = utils.Death
	}
}

func (u *Unit) IsInAttackRange (unit Interface.IUnit) bool {
	if u.attackRange >= math.Sqrt(math.Pow(float64(u.posX - unit.PosX()),2) + math.Pow(float64(u.posZ - unit.PosZ()),2)) {
		return true
	}
	return false
}

func (u *Unit) Move() {
	//只有移动状态和追击状态下才能移动
	if !(u.status == utils.Moving || u.status == utils.Chase) {
		return
	}
	//现在的时间减去上一次移动的时间如果大于移动速度，就应该移动
	t := time.Now()
	if t.Sub(u.lastMoveTime).Seconds() >= u.moveSpeed {
		//Debug
		fmt.Println(t.Sub(u.lastMoveTime).Seconds())

		u.lastMoveTime = t

		//没有路径走不了，或者已经走到终点，变为静止状态，并广播一次消息
		if u.path == nil {
			return
		}

		var updateUnitInfoMsg protobuf.UpdateUnitPosMsg
		updateUnitInfoMsg.UnitId = u.id

		//更新位置
		u.posX = u.path[u.node][0]
		u.posZ = u.path[u.node][1]
		u.node++

		updateUnitInfoMsg.PosX = u.posX
		updateUnitInfoMsg.PosZ = u.posZ
		updateUnitInfoMsg.UnitStatus = u.status
		u.player.GameRoom().Broadcast(protobuf.MsgType_UpdateUnitPos,&updateUnitInfoMsg)

		if u.node >= len(u.path){
			u.status = utils.Static
			updateUnitInfoMsg.PosX = u.posX
			updateUnitInfoMsg.PosZ = u.posZ
			updateUnitInfoMsg.UnitStatus = u.status
			u.player.GameRoom().Broadcast(protobuf.MsgType_UpdateUnitPos,&updateUnitInfoMsg)
			u.path = nil
			u.node = 0
			return
		}
	}
}


//挨打，当别人攻击我时调用此函数
func (u *Unit) Attacked() {

	//如果当前没有目标，并且还被人攻击
	if u.attackTarget == nil && u.attackedTarget != nil {

		if u.IsInAttackRange(u.attackedTarget) {
			u.SetAttackTarget(u.attackedTarget)
			u.SetStatus(utils.Fighting)
		} else {
			//设为挨打状态(追击状态)
			u.status = utils.Attacked

			//给客户端发消息让他往攻击者方向移动
			var attackUnitMsg protobuf.AttackUnitMsg
			attackUnitMsg.UnitIdAttack = u.id
			attackUnitMsg.UnitIdAttacked = u.attackedTarget.Id()
			u.player.User().Connection().SendMsg(protobuf.MsgType_AttackUnit,&attackUnitMsg)
			fmt.Printf("%d号追赶%d号\n",u.id,u.attackedTarget.Id())
		}
	}
}

func (u *Unit) Attack() {
	//只有战斗状态下才能攻击 没有攻击目标
	if u.status != utils.Fighting || u.attackTarget == nil {
		return
	}

	//广播消息
	var attackUnitInfoMsg protobuf.AttackUnitInfoMsg

	//现在的时间减去上一次攻击的时间如果大于攻击速度，就应该攻击
	t := time.Now()
	if t.Sub(u.lastAttackTime).Seconds() >= u.attackSpeed {
		u.lastAttackTime = t

		//判断对方的血量
		if u.attackTarget.NowHp() <= 0 {
			if u.AttackedTarget() == u.AttackTarget() {
				u.SetAttackedTarget(nil)
			}
			u.SetAttackTarget(nil)
			u.SetStatus(utils.Static)

			attackUnitInfoMsg.Id = u.id
			attackUnitInfoMsg.AttackId = 0
			attackUnitInfoMsg.NowHp = u.nowHp
			attackUnitInfoMsg.Status = utils.Static
			u.player.GameRoom().Broadcast(protobuf.MsgType_AttackUnitInfo,&attackUnitInfoMsg)
			return
		}
		//随机，扣血
		u.attackTarget.AddHp(- (rand.Int31n(u.attackPowerUpper - u.attackPowerLower) + u.attackPowerLower))
		//设置攻击对象
		if u.attackTarget.AttackedTarget() == nil && u.NowHp() > 0 && u.attackTarget.NowHp() > 0 {
			u.attackTarget.SetAttackedTarget(u)
			u.attackTarget.Attacked()
		}

		attackUnitInfoMsg.Id = u.id
		attackUnitInfoMsg.NowHp = u.nowHp
		if u.AttackTarget() != nil {
			attackUnitInfoMsg.AttackId = u.AttackTarget().Id()
		}
		attackUnitInfoMsg.Status = u.status
		u.player.GameRoom().Broadcast(protobuf.MsgType_AttackUnitInfo,&attackUnitInfoMsg)

		attackUnitInfoMsg.Id = u.attackTarget.Id()
		attackUnitInfoMsg.NowHp = u.attackTarget.NowHp()
		if u.attackTarget.AttackTarget() != nil {
			attackUnitInfoMsg.AttackId = u.attackTarget.AttackTarget().Id()
		}
		attackUnitInfoMsg.Status = u.attackTarget.Status()
		u.player.GameRoom().Broadcast(protobuf.MsgType_AttackUnitInfo,&attackUnitInfoMsg)
	}
}


//OK
func (u *Unit) AttackTarget() Interface.IUnit {
	return u.attackTarget
}

//OK
func (u *Unit) SetAttackTarget(attackTarget Interface.IUnit) {
	u.attackTarget = attackTarget
}


//加血，减血
func (u *Unit) AddHp(addHp int32) {
	if u.nowHp + addHp >= u.allHp{
		u.nowHp = u.allHp
		return
	}
	atomic.AddInt32(&u.nowHp,addHp)
}

func (u *Unit) Status() int32 {
	return u.status
}

func (u *Unit) SetStatus(status int32) {
	u.status = status
}

func (u *Unit) Path() [][]int32 {
	return u.path
}

func (u *Unit) SetPath(path [][]int32) {
	u.path = path
	u.node = 0
}

func (u *Unit) PosZ() int32 {
	return u.posZ
}

func (u *Unit) SetPosZ(posZ int32) {
	u.posZ = posZ
}

func (u *Unit) PosX() int32 {
	return u.posX
}

func (u *Unit) SetPosX(posX int32) {
	u.posX = posX
}

func (u *Unit) NowHp() int32 {
	return u.nowHp
}

func (u *Unit) SetNowHp(nowHp int32) {
	u.nowHp = nowHp
}

func (u *Unit) AllHp() int32 {
	return u.allHp
}

func (u *Unit) SetAllHp(allHp int32) {
	u.allHp = allHp
}

func (u *Unit) Id() int32 {
	return u.id
}

func (u *Unit) Player() Interface.IPlayer {
	return u.player
}

func (u *Unit) String() string {
	return fmt.Sprintf("%d号玩家的%d号Unit，现在状态为%v，血量为%d\n",u.Player().PlayerId(),u.Id(),u.Status(),u.NowHp())
}